package com.starview.star.operators.arith.runtime;

import java.math.BigDecimal;

import com.starview.platform.data.EvaluationException;
import com.starview.platform.data.IFunction;
import com.starview.platform.data.IValue;
import com.starview.platform.data.type.IType;
import com.starview.platform.data.type.StandardTypes;
import com.starview.platform.data.type.TypeUtils;
import com.starview.platform.data.value.Factory;
import com.starview.star.operators.CafeEnter;

/**
 * Binary arithmetic functions
 * 
 * @author fgm
 * 
 */

public class BignumBinary
{

  public static class BigNumPlus implements IFunction
  {
    @CafeEnter
    public static BigDecimal enter(BigDecimal s1, BigDecimal s2)
    {
      return s1.add(s2);
    }

    @Override
    public IValue enter(IValue... args) throws EvaluationException
    {
      return Factory.newDecimal(enter(Factory.decimalValue(args[0]), Factory.decimalValue(args[1])));
    }

    @Override
    public IType getType()
    {
      return type();
    }

    public static IType type()
    {
      IType decimalType = StandardTypes.rawDecimalType;
      return TypeUtils.functionType(decimalType, decimalType, decimalType);
    }
  }

  public static class BigNumMinus implements IFunction
  {
    @CafeEnter
    public static BigDecimal enter(BigDecimal s1, BigDecimal s2)
    {
      return s1.subtract(s2);
    }

    @Override
    public IValue enter(IValue... args) throws EvaluationException
    {
      return Factory.newDecimal(enter(Factory.decimalValue(args[0]), Factory.decimalValue(args[1])));
    }

    @Override
    public IType getType()
    {
      return type();
    }

    public static IType type()
    {
      IType decimalType = StandardTypes.rawDecimalType;
      return TypeUtils.functionType(decimalType, decimalType, decimalType);
    }
  }

  public static class BigNumTimes implements IFunction
  {
    @CafeEnter
    public static BigDecimal enter(BigDecimal s1, BigDecimal s2)
    {
      return s1.multiply(s2);
    }

    @Override
    public IValue enter(IValue... args) throws EvaluationException
    {
      return Factory.newDecimal(enter(Factory.decimalValue(args[0]), Factory.decimalValue(args[1])));
    }

    @Override
    public IType getType()
    {
      return type();
    }

    public static IType type()
    {
      IType decimalType = StandardTypes.rawDecimalType;
      return TypeUtils.functionType(decimalType, decimalType, decimalType);
    }
  }

  public static class BigNumDivide implements IFunction
  {
    @CafeEnter
    public static BigDecimal enter(BigDecimal s1, BigDecimal s2)
    {
      return s1.divide(s2);
    }

    @Override
    public IValue enter(IValue... args) throws EvaluationException
    {
      return Factory.newDecimal(enter(Factory.decimalValue(args[0]), Factory.decimalValue(args[1])));
    }

    @Override
    public IType getType()
    {
      return type();
    }

    public static IType type()
    {
      IType decimalType = StandardTypes.rawDecimalType;
      return TypeUtils.functionType(decimalType, decimalType, decimalType);
    }
  }

  public static class BigNumRemainder implements IFunction
  {
    @CafeEnter
    public static BigDecimal enter(BigDecimal s1, BigDecimal s2)
    {
      return s1.remainder(s2);
    }

    @Override
    public IValue enter(IValue... args) throws EvaluationException
    {
      return Factory.newDecimal(enter(Factory.decimalValue(args[0]), Factory.decimalValue(args[1])));
    }

    @Override
    public IType getType()
    {
      return type();
    }

    public static IType type()
    {
      IType decimalType = StandardTypes.rawDecimalType;
      return TypeUtils.functionType(decimalType, decimalType, decimalType);
    }
  }

  public static class BigNumMin implements IFunction
  {
    @CafeEnter
    public static BigDecimal enter(BigDecimal s1, BigDecimal s2)
    {
      return s1.min(s2);
    }

    @Override
    public IValue enter(IValue... args) throws EvaluationException
    {
      return Factory.newDecimal(enter(Factory.decimalValue(args[0]), Factory.decimalValue(args[1])));
    }

    @Override
    public IType getType()
    {
      return type();
    }

    public static IType type()
    {
      IType decimalType = StandardTypes.rawDecimalType;
      return TypeUtils.functionType(decimalType, decimalType, decimalType);
    }
  }

  public static class BigNumMax implements IFunction
  {
    @CafeEnter
    public static BigDecimal enter(BigDecimal s1, BigDecimal s2)
    {
      return s1.max(s2);
    }

    @Override
    public IValue enter(IValue... args) throws EvaluationException
    {
      return Factory.newDecimal(enter(Factory.decimalValue(args[0]), Factory.decimalValue(args[1])));
    }

    @Override
    public IType getType()
    {
      return type();
    }

    public static IType type()
    {
      IType decimalType = StandardTypes.rawDecimalType;
      return TypeUtils.functionType(decimalType, decimalType, decimalType);
    }
  }

  public static class BigNumPwr implements IFunction
  {
    @CafeEnter
    public static BigDecimal enter(BigDecimal s1, BigDecimal s2)
    {
      return s1.pow(s2.intValue());
    }

    @Override
    public IValue enter(IValue... args) throws EvaluationException
    {
      return Factory.newDecimal(enter(Factory.decimalValue(args[0]), Factory.decimalValue(args[1])));
    }

    @Override
    public IType getType()
    {
      return type();
    }

    public static IType type()
    {
      IType decimalType = StandardTypes.rawDecimalType;
      return TypeUtils.functionType(decimalType, decimalType, decimalType);
    }
  }
}
